--------------------------------------------------------------------------------
--      Copyright (c) 2015 - 2016 , 蒙占志(topameng) topameng@gmail.com
--      All rights reserved.
--      Use, modification and distribution are subject to the "MIT License"
--------------------------------------------------------------------------------
-- added by wsh @ 2017-12-27
-- 注意：
-- 1、已经被修改，别从tolua轻易替换来做升级

local setmetatable = setmetatable
local xpcall       = xpcall
local pcall        = pcall
local assert       = assert
local rawget       = rawget
local error        = error
local traceback    = debug.traceback
local ilist        = ilist

event_err_handle   = function(msg)
    error(msg, 2)
end

local _pcall       = {
    __call = function(self, ...)
        local status, err
        if not self.obj then
            status, err = pcall(self.func, ...)
        else
            status, err = pcall(self.func, self.obj, ...)
        end
        if not status then
            event_err_handle(err .. "\n" .. traceback())
        end
        return status
    end,

    __eq   = function(lhs, rhs)
        return lhs.func == rhs.func and lhs.obj == rhs.obj
    end,
}

local function functor(func, obj)
    return setmetatable({ func = func, obj = obj }, _pcall)
end

local _event   = {}
_event.__index = _event

function _event:CreateListener(func, obj)
    func = functor(func, obj)
    return { value = func, _prev = 0, _next = 0, removed = true }
end

function _event:AddListener(handle)
    assert(handle)

    if self.lock then
        table.insert(self.opList, function()
            self.list:pushnode(handle)
        end)
    else
        self.list:pushnode(handle)
    end
end

function _event:RemoveListener(handle)
    assert(handle)

    if self.lock then
        table.insert(self.opList, function()
            self.list:remove(handle)
        end)
    else
        self.list:remove(handle)
    end
end

function _event:Count()
    return self.list.length
end

function _event:Clear()
    self.list:clear()
    self.opList  = {}
    self.lock    = false
    self.current = nil
end

_event.__call = function(self, ...)
    local _list = self.list
    self.lock   = true
    local ilist = ilist

    for i, f in ilist(_list) do
        self.current = i
        if not f(...) then
            _list:remove(i)
            self.lock = false
        end
    end

    local opList = self.opList
    self.lock    = false

    for i, op in ipairs(opList) do
        op()
        opList[i] = nil
    end
end

function event(name)
    return setmetatable({
                            name   = name,
                            lock   = false,
                            opList = {},
                            list   = list:new(),
                        }, _event)
end

UpdateBeat        = event("Update")
LateUpdateBeat    = event("LateUpdate")
FixedUpdateBeat   = event("FixedUpdate")
--只在协同使用
CoUpdateBeat      = event("CoUpdate")
CoLateUpdateBeat  = event("CoLateUpdate")
CoFixedUpdateBeat = event("CoFixedUpdate")

function Update(deltaTime, unscaledDeltaTime)
    Time:SetDeltaTime(deltaTime, unscaledDeltaTime)
    UpdateBeat()
    CoUpdateBeat()
end

function LateUpdate()
    LateUpdateBeat()
    CoLateUpdateBeat()
    Time:SetFrameCount()
end

function FixedUpdate(fixedDeltaTime)
    Time:SetFixedDelta(fixedDeltaTime)
    FixedUpdateBeat()
    CoFixedUpdateBeat()
end